#include <iostream>
#include <vector>
#include <functional>  // for std::bind
#include <typeinfo>
 
using namespace std::placeholders;  //让_1, _2, _3,...可见！
using namespace std;
 
//除法函数：x/y
double my_divide(double x, double y)
{
    return x / y;
}
 
class MyPair
{
public:
    double a, b;
    MyPair(int a, int b):a(a), b(b)
    {
        
        cout << "MyPair(int a, int b)" << endl;
    }
    //注意成员函数的第1个参数是this!!!
    double mutiply(){return a * b;}

    int add(int a, int b, int c)
    {
        return a + b + c;
    }
};
 
int main()
{
    //1、绑定函数
    auto fn1 = bind(my_divide, 10, 2); //返回一个std::function类型的仿函数
    //function<double(void)> fn1 = bind(my_divide, 10, 2); //绑定完，fn1是无参，所以为void
    //cout << typeid(fn1).name() << endl;
    cout << fn1() << endl;
    
    auto fn2 = bind(my_divide, _1, 2); //my_divide的第2个参数绑定为2
    cout << fn2(10) << endl;     // 输出5
    //cout << fn2(10, 3) << endl;  // 输出仍然为5！
    
    auto fn3 = bind(my_divide, _2, _1);
    cout << fn3(10, 2) << endl; //输出：0.2。注意10为第1个参数，被绑到_1的位置，2绑到_2的位置
    
    auto fn4 = bind<int>(my_divide, _1, _2); //指定返回值为int型
    cout << fn4(10, 3) << endl;
    
    //2、绑定类的成员
    MyPair mp{10, 2}; //注意，mp是个聚合对象，可用{}直接初始化（虽无2个参数的构造函数）。
    
    auto ftor_memfn = bind(&MyPair::mutiply, _1); //成员函数，其实有个this指针，须放入_1
    cout << ftor_memfn(mp) << endl; //20，传入mp对象的地址（这里传的是引用）
    
    auto padd = bind(&MyPair::add,mp,_1,_2,0);
    padd(5,6);
    
    cout << "a = " << mp.a << endl;
    cout << "b = " << mp.b << endl;

    auto mpa = bind(&MyPair::a, mp);

    mpa(mp) = 100;
    cout << mp.a << endl;
    cout << "a = " << mp.a << endl;
    cout << "b = " << mp.b << endl;







    auto ftor_memdata = bind(&MyPair::a, mp); //传mp对象的副本，
    //auto ftor_memdata = bind(&MyPair::a, &mp); //传mp的地址
    cout << ftor_memdata() << endl;  //10
    ftor_memdata() = 100;  //mp副本的a值被改为100
    cout << mp.a << endl;  //10，mp本身的a值未被改变，仍为10
    cout << ftor_memdata() << endl;
    
    auto ftor_memdata2 = bind(&MyPair::b, _1);
    cout << ftor_memdata2(mp) << endl;  //2
    ftor_memdata2(mp) = 50;  //传mp的引用
    cout << mp.b << endl;    //由于按引用传递，b的值被改！
    cout << ftor_memdata2(mp) << endl;
    
    return 0;
}
